package cn.sciento.transfer.domain.entity;

import com.fasterxml.jackson.annotation.JsonInclude;
import cn.sciento.core.exception.CommonException;import io.choerodon.mybatis.annotation.ModifyAudit;
import io.choerodon.mybatis.annotation.VersionAudit;
import io.choerodon.mybatis.domain.AuditDomain;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.Date;
import java.util.List;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.validation.constraints.NotNull;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.hibernate.validator.constraints.NotBlank;
import cn.sciento.boot.platform.lov.annotation.LovValue;
import cn.sciento.core.base.BaseConstants;
import cn.sciento.starter.keyencrypt.core.Encrypt;
import cn.sciento.transfer.domain.repository.ConsDbConfigRepository;
import cn.sciento.transfer.infra.constant.Constants;
import org.springframework.util.Assert;

@ApiModel("数据消息消费DB配置")
@VersionAudit
@ModifyAudit
@Table(name = "hdtt_cons_db_config")
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ConsDbConfig extends AuditDomain {
  public static final String ENCRYPT_KEY = "hdtt_cons_db_config";
  
  public static final String FIELD_CONS_DB_CONFIG_ID = "consDbConfigId";
  
  public static final String FIELD_PRODUCER_CONFIG_ID = "producerConfigId";
  
  public static final String FIELD_CONSUMER_TABLE = "consumerTable";
  
  public static final String FIELD_CONSUMER_SERVICE = "consumerService";
  
  public static final String FIELD_CONSUMER_DS = "consumerDs";
  
  public static final String FIELD_CONSUMER_DB = "consumerDb";
  
  public static final String FIELD_CONSUMER_OFFSET = "consumerOffset";
  
  public static final String FIELD_PROCESS_TIME = "processTime";
  
  public static final String FIELD_PROCESS_STATUS = "processStatus";
  
  public static final String FIELD_PROCESS_MSG = "processMsg";
  
  public static final String FIELD_ENABLED_FLAG = "enabledFlag";
  
  @Encrypt
  @ApiModelProperty("表ID，主键")
  @Id
  @GeneratedValue
  private Long consDbConfigId;
  
  @Encrypt
  @ApiModelProperty("消息生产配置，获取topic")
  @NotNull
  private Long producerConfigId;
  
  @ApiModelProperty("消费对应的表，默认跟消息生产表一样")
  @NotBlank
  private String consumerTable;
  
  @ApiModelProperty("消费服务")
  @NotBlank
  private String consumerService;
  
  @ApiModelProperty("数据源ID")
  @NotNull
  private Long consumerDsId;
  
  @ApiModelProperty("数据源编码")
  @NotBlank
  private String consumerDs;
  
  @ApiModelProperty("DB编码")
  @NotBlank
  private String consumerDb;
  
  @ApiModelProperty("消费消息偏移起始数")
  @NotNull
  private Long consumerOffset;
  
  @ApiModelProperty("处理时间")
  private Date processTime;
  
  @ApiModelProperty("处理状态，参考：HDTT_EVENT_PROCESS_STATUS")
  @NotBlank
  @LovValue(lovCode = "HDTT.EVENT_PROCESS_STATUS", meaningField = "processStatusMeaning")
  private String processStatus;
  
  @ApiModelProperty("初始化处理消息")
  private String processMsg;
  
  @ApiModelProperty("是否启用。1启用，0未启用")
  @NotNull
  private Integer enabledFlag;
  
  @Transient
  private List<ConsTenantConfig> consTenantConfigList;
  
  @Transient
  private String consumerServiceName;
  
  @Transient
  private String processStatusMeaning;
  
  @Transient
  private Integer initByDbDimension;
  
  @Transient
  private Long tenantId;
  
  public void validUnique(ConsDbConfigRepository consDbConfigRepository) {
    ConsDbConfig querry = new ConsDbConfig();
    querry.setConsumerTable(getConsumerTable());
    querry.setConsumerService(getConsumerService());
    querry.setConsumerDs(getConsumerDs());
    querry.setConsumerDb(getConsumerDb());
    if (CollectionUtils.isNotEmpty(consDbConfigRepository.select(querry)))
      throw new CommonException("error.cons.db.config.exist", new Object[] { getConsumerTable(), getConsumerService() }); 
  }
  
  public void init() {
    if (this.consumerOffset == null)
      this.consumerOffset = Long.valueOf(0L); 
    if (this.enabledFlag == null)
      this.enabledFlag = BaseConstants.Flag.YES; 
    setProcessStatus("P");
  }
  
  public void validInitHistoryDataStatus(ProducerConfig producerConfig, ConsDbConfigRepository consDbConfigRepository, boolean disableProcessExistsDb) {
    ConsDbConfig consDbConfig = (ConsDbConfig)consDbConfigRepository.selectByPrimaryKey(this.consDbConfigId);
    Assert.notNull(consDbConfig, "error.data_invalid");
    if (!BaseConstants.Flag.YES.equals(consDbConfig.getEnabledFlag()) || 
      !BaseConstants.Flag.YES.equals(producerConfig.getEnabledFlag()))
      throw new CommonException("error.current_config_disable");
    if (initByDbDimension() && "R".equals(consDbConfig.getProcessStatus()))
      throw new CommonException("error.init.another_is_processing", new Object[] { this.consumerService }); 
    if (initByDbDimension() && 
      "S".equals(consDbConfig.getProcessStatus()) && disableProcessExistsDb)
      throw new CommonException("error.init.disable_process_exists_db", new Object[] { this.consumerService }); 
    if (!initByDbDimension() && CollectionUtils.isNotEmpty(this.consTenantConfigList))
      this.consTenantConfigList.forEach(item -> {
            if ("R".equals(item.getProcessStatus()))
              throw new CommonException("error.init.tenant.is.running", new Object[] { item.getTenantName(), this.consumerService }); 
            if ("S".equals(item.getProcessStatus()) && disableProcessExistsDb)
              throw new CommonException("error.init.tenant.is.completed", new Object[] { item.getTenantName(), this.consumerService }); 
          }); 
    if (initByDbDimension()) {
      if (BaseConstants.Flag.YES.equals(producerConfig.getTenantFlag()))
        throw new CommonException("error.dimension.not.matched");
    } else {
      Assert.isTrue(CollectionUtils.isNotEmpty(getConsTenantConfigList()), "error.data_invalid");
      if (!BaseConstants.Flag.YES.equals(producerConfig.getTenantFlag()))
        throw new CommonException("error.dimension.not.matched");
    } 
  }
  
  public boolean initByDbDimension() {
    return BaseConstants.Flag.YES.equals(this.initByDbDimension);
  }
  
  public String generateConsumerGroup(ConsTenantConfig consTenantConfig) {
    return this.consumerDs.replaceAll("\\.", "_") + "%" + this.consumerService + "%" + this.consumerDb + "%" + this.consumerTable + ((consTenantConfig == null) ? "%null" : ("%" + consTenantConfig
      
      .getTenantId()));
  }
  
  public static ConsDbConfig parseConsumerGroup(String group) {
    String[] groupParts = group.split("%");
    if (ArrayUtils.isEmpty((Object[])groupParts) || groupParts.length != 5)
      return null; 
    String consumerDs = groupParts[0].replaceAll("_", ".");
    ConsDbConfig consDbConfig = new ConsDbConfig();
    consDbConfig.setConsumerDs(consumerDs);
    consDbConfig.setConsumerService(groupParts[1]);
    consDbConfig.setConsumerDb(groupParts[2]);
    consDbConfig.setConsumerTable(groupParts[3]);
    consDbConfig.setTenantId(groupParts[4].equals("null") ? null : Long.valueOf(Long.parseLong(groupParts[4])));
    return consDbConfig;
  }
  
  public String getConsumerTlTable() {
    return this.consumerTable + Constants.TableNameSuffix.TLS.suffix();
  }
  
  @Transient
  private Boolean offsetChangeFlag = Boolean.FALSE;
  
  @Transient
  private String consumerEvent;
  
  @Transient
  private String consumerEventArch;
  
  @Transient
  private String consumerFullTableName;
  
  @Transient
  private String consumerFullTableTLName;
  
  @Transient
  private Boolean multiLangConsumerFlag;
  
  public Long getConsDbConfigId() {
    return this.consDbConfigId;
  }
  
  public void setConsDbConfigId(Long consDbConfigId) {
    this.consDbConfigId = consDbConfigId;
  }
  
  public Long getProducerConfigId() {
    return this.producerConfigId;
  }
  
  public void setProducerConfigId(Long producerConfigId) {
    this.producerConfigId = producerConfigId;
  }
  
  public String getConsumerTable() {
    return this.consumerTable;
  }
  
  public void setConsumerTable(String consumerTable) {
    this.consumerTable = consumerTable;
  }
  
  public String getConsumerService() {
    return this.consumerService;
  }
  
  public void setConsumerService(String consumerService) {
    this.consumerService = consumerService;
  }
  
  public String getConsumerDs() {
    return this.consumerDs;
  }
  
  public void setConsumerDs(String consumerDs) {
    this.consumerDs = consumerDs;
  }
  
  public String getConsumerDb() {
    return this.consumerDb;
  }
  
  public void setConsumerDb(String consumerDb) {
    this.consumerDb = consumerDb;
  }
  
  public Long getConsumerOffset() {
    return this.consumerOffset;
  }
  
  public void setConsumerOffset(Long consumerOffset) {
    this.consumerOffset = consumerOffset;
  }
  
  public Date getProcessTime() {
    return this.processTime;
  }
  
  public void setProcessTime(Date processTime) {
    this.processTime = processTime;
  }
  
  public String getProcessStatus() {
    return this.processStatus;
  }
  
  public void setProcessStatus(String processStatus) {
    this.processStatus = processStatus;
  }
  
  public String getProcessMsg() {
    return this.processMsg;
  }
  
  public void setProcessMsg(String processMsg) {
    this.processMsg = processMsg;
  }
  
  public ConsDbConfig addProcessMsg(String processMsg) {
    this.processMsg += processMsg + "\n";
    return this;
  }
  
  public Integer getEnabledFlag() {
    return this.enabledFlag;
  }
  
  public void setEnabledFlag(Integer enabledFlag) {
    this.enabledFlag = enabledFlag;
  }
  
  public Long getConsumerDsId() {
    return this.consumerDsId;
  }
  
  public void setConsumerDsId(Long consumerDsId) {
    this.consumerDsId = consumerDsId;
  }
  
  public String getConsumerServiceName() {
    return this.consumerServiceName;
  }
  
  public void setConsumerServiceName(String consumerServiceName) {
    this.consumerServiceName = consumerServiceName;
  }
  
  public String getProcessStatusMeaning() {
    return this.processStatusMeaning;
  }
  
  public void setProcessStatusMeaning(String processStatusMeaning) {
    this.processStatusMeaning = processStatusMeaning;
  }
  
  public Integer getInitByDbDimension() {
    return this.initByDbDimension;
  }
  
  public void setInitByDbDimension(Integer initByDbDimension) {
    this.initByDbDimension = initByDbDimension;
  }
  
  public List<ConsTenantConfig> getConsTenantConfigList() {
    return this.consTenantConfigList;
  }
  
  public void setConsTenantConfigList(List<ConsTenantConfig> consTenantConfigList) {
    this.consTenantConfigList = consTenantConfigList;
  }
  
  public Long getTenantId() {
    return this.tenantId;
  }
  
  public void setTenantId(Long tenantId) {
    this.tenantId = tenantId;
  }
  
  public Boolean getOffsetChangeFlag() {
    return this.offsetChangeFlag;
  }
  
  public void setOffsetChangeFlag(Boolean offsetChangeFlag) {
    this.offsetChangeFlag = offsetChangeFlag;
  }
  
  public String getConsumerEvent() {
    return this.consumerEvent;
  }
  
  public void setConsumerEvent(String consumerEvent) {
    this.consumerEvent = consumerEvent;
  }
  
  public String getConsumerEventArch() {
    return this.consumerEventArch;
  }
  
  public void setConsumerEventArch(String consumerEventArch) {
    this.consumerEventArch = consumerEventArch;
  }
  
  public String getConsumerFullTableName() {
    return this.consumerFullTableName;
  }
  
  public void setConsumerFullTableName(String consumerFullTableName) {
    this.consumerFullTableName = consumerFullTableName;
  }
  
  public Boolean getMultiLangConsumerFlag() {
    return this.multiLangConsumerFlag;
  }
  
  public void setMultiLangConsumerFlag(Boolean multiLangConsumerFlag) {
    this.multiLangConsumerFlag = multiLangConsumerFlag;
  }
  
  public String getConsumerFullTableTLName() {
    return this.consumerFullTableTLName;
  }
  
  public void setConsumerFullTableTLName(String consumerFullTableTLName) {
    this.consumerFullTableTLName = consumerFullTableTLName;
  }
  
  public String toString() {
    return (new ToStringBuilder(this))
      .append("consDbConfigId", this.consDbConfigId)
      .append("producerConfigId", this.producerConfigId)
      .append("consumerTable", this.consumerTable)
      .append("consumerService", this.consumerService)
      .append("consumerDsId", this.consumerDsId)
      .append("consumerDs", this.consumerDs)
      .append("consumerDb", this.consumerDb)
      .append("consumerOffset", this.consumerOffset)
      .append("processTime", this.processTime)
      .append("processStatus", this.processStatus)
      .append("processMsg", this.processMsg)
      .append("enabledFlag", this.enabledFlag)
      .append("consTenantConfigList", this.consTenantConfigList)
      .append("consumerServiceName", this.consumerServiceName)
      .append("processStatusMeaning", this.processStatusMeaning)
      .append("initByDbDimension", this.initByDbDimension)
      .append("tenantId", this.tenantId)
      .append("offsetChangeFlag", this.offsetChangeFlag)
      .append("consumerEvent", this.consumerEvent)
      .append("consumerEventArch", this.consumerEventArch)
      .append("consumerFullTableName", this.consumerFullTableName)
      .append("consumerFullTableTLName", this.consumerFullTableTLName)
      .append("multiLangConsumerFlag", this.multiLangConsumerFlag)
      .toString();
  }
}
